Traditionally, shaders, such as software programs that extend functionality of graphics acceleration hardware, have been authored in machine code. More recently, however, shaders have been written in higher-level languages, and then compiled into machine code by compilers. The compiled shaders are then executed on graphic acceleration hardware to display the desired result. The complexity of these shader programs have continued to increase as the demands for more compelling and realistic graphics have also increased. Further, the recent introduction of general computing on graphics hardware has increased the complexity of these devices even more. Shader programs typically have requirements that restrict the types of calculations that can be executed in different scenarios. These restrictions are due, in part, to the complexity of shader programs running potentially thousands of threads of execution simultaneously, compounded by the necessity for the programs to optimally run on various types of hardware. Other restrictions are due to the way graphics hardware is set up, such that it is built to enable thousands of threads to run efficiently, which dictates restrictions on how programs access memory and how much threads can vary from each other. Some of these restrictions include operations that cannot execute in varying flow-control or on data that may be varying, or operations that cannot be executed on data coming from certain types of resources.
Compilers require knowledge about the values involved in the compilation in order to perform optimizations, such as bits that are known to be a certain value, ranges that a value can have, and whether a value may be a special nonmathematical value, such as not a number or infinity. Previously, in order to calculate this information in code that contains loops or circular dependencies, a compiler would start with a conservative guess and would simulate execution of a loop until it converged on an acceptable answer. This, however, resulted in the compiler being too conservative, resulting in less optimization, in addition to a significant amount of time being required to execute the task. Further, there have traditionally been separate, but overlapping systems for each type of information being calculated, which expends unnecessary time and resources, including execution time of the compiler.